#include"DealReq.h"
#include"DealRet.h"
#include<sstream>
#include<regex>
#include<iostream>
#include"Req.h"
#include<stdlib.h>
#include"Header.h"
#include"DealConn.h"
#include<thread>
#include<stdio.h>
#include"Log.h"

std::atomic_flag DealReq::lock_sts = ATOMIC_FLAG_INIT;

std::unordered_map<std::string, std::function<std::string(int)>> DealReq::UTF;
std::unordered_map<int, std::shared_ptr<Req>> DealReq::STS;

void DealReq::readData(int fd){
  auto &&req = getReq(fd);
  if(req){
    char buf[size];
    int rn;
    while(true){
      rn = read(fd, buf, size);
      if(rn == -1){
	if(req->overHead && req->bl == 0){
	  req->dealData();
	  dealFunc(fd);
	}
	break;
      }else if(rn == 0){
	break;
      }else{
	req->body.write(buf, rn);
	if(!req->overHead){
	  if(std::regex_match(req->body.str(), std::regex("[\\S\\s]+?\r\n\r\n[\\s\\S]*"))){
	    req->startBody();
	  }
	}else{
	  req->bl -= rn;
	}
      }
    }
  }
}


void DealReq::dealReq(int fd){
  if(STS.find(fd) == STS.end()){
    addReq(fd);
    readData(fd);
  }else{
    auto &&req = getReq(fd);
    if(req && req->bl != 0){
      readData(fd);
    }
  }
}

void DealReq::dealFunc(int fd){
  auto req = getReq(fd);
  if(req){
    auto &rhead = req->head;
    auto &&ret = std::make_shared<Ret>();
    DealRet::addRet(ret, fd);
    auto &head = ret->head;
    if(UTF.find(rhead->ss) == UTF.end()){
      head->setLM("resources/static/" + rhead->ss);
      if(head->h.find(Header::k[4]) == head->h.end()){
	head->seterror(ret->body, ret->s);
      }else if(rhead->h.find("if-modified-since:") == rhead->h.end()){
	head->setsct(rhead->ss, ret->body, ret->s);
      }else{
	std::string rlm = rhead->h["if-modified-since:"];
	if(rlm == head->h[Header::k[4]]){
	  head->ss = "304";
	  head->st = "Not Modified";
	  head->get(ret->s);
	}else{
	  head->setsct(rhead->ss, ret->body, ret->s);
	}
      }
    }else{
      std::string &&msg = UTF[rhead->ss](fd);
      head->setdct(msg, ret->body, ret->s);
    }
    std::string ctl = head->h.find("Content-Length:") == head->h.end() ? "0" : head->h["Content-Length:"]; 
    Log::log(fd, rhead->getl(), head->ss, ctl);
    eraseReq(fd);
    DealConn::resetfd(fd);
  }
}

void DealReq::addReq(int fd){
  while(lock_sts.test_and_set()) std::this_thread::yield();
  STS[fd] = std::make_shared<Req>();
  lock_sts.clear();
}

void DealReq::eraseReq(int fd){
  while(lock_sts.test_and_set()) std::this_thread::yield();
  STS.erase(fd);
  lock_sts.clear();
}

std::shared_ptr<Req> DealReq::getReq(int fd){
  std::shared_ptr<Req> req;
  while(lock_sts.test_and_set()) std::this_thread::yield();
  if(STS.find(fd) != STS.end())
    req = STS[fd];
  lock_sts.clear();
  return req;
}
